package org.thanos.simulator.page;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import org.thanos.bacnet.exception.BACnetServiceException;
import org.thanos.bacnet.obj.BACnetObject;
import org.thanos.bacnet.type.enumerated.PropertyIdentifier;
import org.thanos.simulator.api.BACnetIpClient;
import org.thanos.simulator.page.network.NetworkConfigPage;
import org.thanos.simulator.page.point.ObjectConfigPage;

import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

public class IndexPage {

    private final JFrame jFrame;
    private final JSplitPane jSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);;
    private JScrollPane jScrollPane;
    private JPopupMenu jPopupMenu;
    private JPopupMenu jObjectPopupMenu;
    private JTable jTable;
    private JTree jTree;
    private TreePath currentTreePath;

    public IndexPage() {
        jFrame = new JFrame("BACNet 模拟器");
        jFrame.setSize(600, 400);
        jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);// 设置关闭退出
        jFrame.setLayout(new BorderLayout());
        jFrame.setVisible(true);
        this.reloadMenu();
        this.initPopMenu();
        this.initObjectPopMenu();
    }

    /**
     * build menu
     *
     * @return
     */
    private JMenuBar configMenuBar() {
        JMenuBar menuBar = new JMenuBar();
        JMenu menu1 = new JMenu("文件");
        menuBar.add(menu1);
        JMenuItem networkMenu = new JMenuItem("配置本地网络");
        networkMenu.setEnabled(!BACnetIpClient.isInitialized());
        networkMenu.addActionListener(e -> SwingUtilities.invokeLater(() -> {
            new NetworkConfigPage(this);
        }));
        menu1.add(networkMenu);
        JMenuItem stopMenu = new JMenuItem("停止运行");
        stopMenu.setEnabled(BACnetIpClient.isInitialized());
        stopMenu.addActionListener(e -> SwingUtilities.invokeLater(() -> {
            BACnetIpClient.stop();
            jFrame.getContentPane().removeAll();
            this.reloadMenu();
        }));
        menu1.add(stopMenu);
        return menuBar;
    }

    /**
     * 构建树
     *
     * @return
     */
    private JScrollPane createTree() {
        if (CharSequenceUtil.isNotBlank(BACnetIpClient.getRootDeviceName())) {
            DefaultMutableTreeNode mutableTreeNode = new DefaultMutableTreeNode();
            mutableTreeNode.setUserObject(BACnetIpClient.getRootDeviceName());
            List<BACnetObject> objects = BACnetIpClient.getObjectNames();
            if (CollUtil.isNotEmpty(objects)) {
                List<String> list = objects.stream().map(BACnetObject::getObjectName).collect(Collectors.toList());
                if (CollUtil.isNotEmpty(list)) {
                    for (String objectName : list) {
                        DefaultMutableTreeNode treeNode = new DefaultMutableTreeNode(objectName);
                        mutableTreeNode.add(treeNode);
                    }
                }
            }
            jTree = new JTree(mutableTreeNode);
            jTree.addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    Point point = e.getPoint();
                    TreePath path = jTree.getClosestPathForLocation(point.x, point.y);
                    if (SwingUtilities.isLeftMouseButton(e)) {
                        setCurrentTreePath(path);
                        renderContext(path);
                    } else if (SwingUtilities.isRightMouseButton(e)) {
                        jTree.setSelectionPath(path);
                        if (Objects.isNull(path.getParentPath())) {
                            jPopupMenu.show(jScrollPane, e.getX(), e.getY());
                        } else {
                            jObjectPopupMenu.show(jScrollPane, e.getX(), e.getY());
                        }
                    }
                }
            });
            jScrollPane = new JScrollPane(jTree);
            jScrollPane.setVisible(true);
        }
        return jScrollPane;
    }

    private void initPopMenu() {
        jPopupMenu = new JPopupMenu();
        JMenuItem menuItem1 = new JMenuItem("创建模拟点");
        jPopupMenu.add(menuItem1);
        menuItem1.addActionListener(e -> {
            if (!BACnetIpClient.isInitialized()) {
                JOptionPane.showMessageDialog(null, "本地网络没有初始化", "提示", JOptionPane.ERROR_MESSAGE);
                return;
            }
            javax.swing.SwingUtilities.invokeLater(() -> new ObjectConfigPage(this));
        });
    }

    private void initObjectPopMenu() {
        jObjectPopupMenu = new JPopupMenu();
        JMenuItem menuItem1 = new JMenuItem("删除");
        jObjectPopupMenu.add(menuItem1);
        menuItem1.addActionListener(e -> {
            if (!BACnetIpClient.isInitialized()) {
                JOptionPane.showMessageDialog(null, "本地网络没有初始化", "提示", JOptionPane.ERROR_MESSAGE);
                return;
            }
            if (Objects.nonNull(jTree)) {
                TreePath path = jTree.getSelectionPath();
                if (Objects.nonNull(path)) {
                    String objectName = path.getLastPathComponent().toString();
                    try {
                        BACnetIpClient.removeObject(objectName);
                        this.reloadTree();
                        if (Objects.nonNull(jTable)) {
                            jFrame.getContentPane().remove(jTable);
                            jTable = null;
                            jFrame.repaint();
                            jFrame.setVisible(true);
                        }
                    } catch (BACnetServiceException ex) {
                        throw new RuntimeException(ex);
                    }
                }
            }
        });
    }

    public void reloadMenu() {
        if (Objects.nonNull(jFrame.getJMenuBar())) {
            jFrame.remove(jFrame.getJMenuBar());
        }
        jFrame.setJMenuBar(this.configMenuBar());
        jFrame.repaint();
        jFrame.setVisible(true);
    }

    public void reloadTree() {
        if (Objects.nonNull(jScrollPane) && jFrame.getContentPane().contains(jScrollPane.getLocation())) {
            jFrame.getContentPane().remove(jScrollPane);
        }
        jSplitPane.setLeftComponent(this.createTree());
        jFrame.getContentPane().add(jSplitPane);
        jFrame.repaint();
        jFrame.setVisible(true);
    }

    /**
     * 渲染点击左键的内容
     */
    public void renderContext(TreePath path) {
        List<BACnetObject> baCnetObjectList = BACnetIpClient.getObjectNames();
        if (CollUtil.isEmpty(baCnetObjectList)) {
            return;
        }
        BACnetObject object = baCnetObjectList.stream().filter(baCnetObject -> baCnetObject.getObjectName().equals(path.getLastPathComponent().toString())).findAny().orElse(null);
        if (Objects.isNull(object)) {
            return;
        }
        try {
            List<PropertyIdentifier> propertyIdentifiers = Arrays.asList(PropertyIdentifier.presentValue,
                    PropertyIdentifier.objectName, PropertyIdentifier.objectType, PropertyIdentifier.objectIdentifier, PropertyIdentifier.eventState,
                    PropertyIdentifier.units, PropertyIdentifier.outOfService, PropertyIdentifier.statusFlags, PropertyIdentifier.stateText);
            String[] columns = new String[]{"property", "value"};
            // 表格中的内容，是一个二维数组
            String[][] values = new String[propertyIdentifiers.size()][];
            for (int i = 0; i < propertyIdentifiers.size(); i++) {
                values[i] = new String[2];
                values[i][0] = propertyIdentifiers.get(i).toString();
                values[i][1] = Objects.nonNull(object.readProperty(propertyIdentifiers.get(i))) ? object.readProperty(propertyIdentifiers.get(i)).toString() : CharSequenceUtil.EMPTY;
            }
            if (Objects.nonNull(jTable) && jFrame.getContentPane().contains(jTable.getLocation())) {
                jFrame.getContentPane().remove(jTable);
                jTable = null;
            }
            jTable = new JTable(values, columns);
            jSplitPane.setRightComponent(jTable);
            jFrame.getContentPane().add(jSplitPane);
            jFrame.repaint();
            jFrame.setVisible(true);
        } catch (BACnetServiceException ex) {
            throw new RuntimeException(ex);
        }
    }

    public TreePath getCurrentTreePath() {
        return currentTreePath;
    }

    public void setCurrentTreePath(TreePath currentTreePath) {
        this.currentTreePath = currentTreePath;
    }
}
